<?php

declare(strict_types=1);

namespace RX\Component\DB\EasyPdo;

use RuntimeException;
use RX\Exception\PoolEmptyException;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;

class Connection
{
    /**
     * @var PDOPool
     */
    protected PDOPool $pools;

    private static $instance;

    /**
     * @var array
     */
    protected $config = [
        'host'       => 'localhost',
        'port'       => 3306,
        'database'   => 'test',
        'username'   => 'root',
        'password'   => 'root',
        'charset'    => 'utf8mb4',
        'unixSocket' => null,
        'options'    => [],
        'size'       => 64,
    ];

    private function __construct(array $config)
    {
        if (empty($this->pools)) {
            $this->config = array_replace_recursive($this->config, $config);
            try {
                $this->pools = new PDOPool(
                    (new PDOConfig())
                        ->withHost($this->config['host'])
                        ->withPort($this->config['port'])
                        ->withUnixSocket($this->config['unixSocket'])
                        ->withDbName($this->config['database'])
                        ->withCharset($this->config['charset'])
                        ->withUsername($this->config['username'])
                        ->withPassword($this->config['password'])
                        ->withOptions($this->config['options']),
                    $this->config['size']
                );
            } catch (\Throwable $e) {
                var_dump($e->getMessage());
            }
        }
    }

    public static function getInstance($config = null, $poolName = 'default')
    {
        if (empty(self::$instance[$poolName])) {
            if (empty($config)) {
                throw new RuntimeException('pdo config empty');
            }
            if (empty($config['size'])) {
                throw new RuntimeException('the size of database connection pools cannot be empty');
            }
            self::$instance[$poolName] = new static($config);
        }
        return self::$instance[$poolName];
    }

    public function getConnection()
    {
        $connection = $this->pools->get();
        if (empty($connection)) {
            throw new PoolEmptyException("pool is empty");
        }
        return $connection;
    }

    public function close($connection = null)
    {
        $this->pools->put($connection);
    }
}
